#pragma once

#include <iostream>
#include <string>
#include <ctime>
#include <sstream>
#include <exception>
#include <cstdint>
#include <cstring>
#include <cerrno>
#include <thread>

namespace Server
{
    // 日志级别枚举
    enum LogLevel {
        DEBUG = 0,
        NORMAL,
        WARNING,
        ERROR,
        FATAL
    };

    // 将日志级别转换为字符串
    const char* to_level(LogLevel level) {
        switch (level) {
            case DEBUG:   return "DEBUG";
            case NORMAL:  return "NORMAL";
            case WARNING: return "WARNING";
            case ERROR:   return "ERROR";
            case FATAL:   return "FATAL";
            default:      return nullptr;
        }
    }

    // 获取当前时间的字符串表示
    std::string current_time() {
        std::time_t now = std::time(nullptr);
        std::tm* localtime = std::localtime(&now);
        char timeStr[20];
        std::strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", localtime);
        return std::string(timeStr);
    }

    // [日记等级][线程ID][时间][文件名:行数] message
    class LogException : public std::exception {
    public:
        template <typename... Args>
        LogException(LogLevel level, const std::string& message, const std::string& filepath, const uint32_t line, Args... args) {
            std::ostringstream oss;
            oss << "[" << to_level(level) << "][" << std::this_thread::get_id() << "][" << current_time() << "][" << filepath << ":" << line << "] " << message;

            std::ostringstream msgStream;
            (msgStream << ... << args);

            oss << " " << msgStream.str();
            _msg = oss.str();
        }

        const char* what() const noexcept override {
            return _msg.c_str();
        }

    private:
        std::string _msg;
    };

    // 辅助函数，用于抛出异常并自动传递文件名和行号
    template <typename... Args>
    void throw_log_exception(LogLevel level, const std::string& message, const std::string& filepath, const uint32_t line, Args... args) {
        throw LogException(level, message, filepath, line, args...);
    }

    // 辅助宏，用于捕获文件名和行号
    #define THROW_EXCEPTION(level, message, ...) do { throw_log_exception(level, message, __FILE__, __LINE__, ##__VA_ARGS__); } while(0)
}
